Release 10.1A: OpenEdge Development:
ProDataSets
Creating a data access procedure for the Order ProDataSet
The first step is to create a data access procedure that handles all the code that requires knowledge of the data source. To do this, you create a procedure to act as the data access object for the
dsOrderProDataSet in the same way thatCodeSource.pdoes for the code table ProDataSet from the previous chapter. Figure 10–1 illustrates the kinds of data definitions and logic to consider as part of the data access object.Figure 10–1: Data access procedure
![]()
Figure 10–1 illustrates:
- The data access object encapsulates all database references. Therefore, query definitions are part of the object.
- Data-Source definitions that map database tables and queries to ProDataSet buffers are part of the object.
- Methods (internal procedures or functions) that attach and detach Data-Sources for the ProDataSet buffers are part of the object.
- Methods that prepare database queries or methods that in other ways reference database table and field names directly are part of the object. For example, one kind of request of the
OrderProDataSet is to return all the data for a particularOrdernumber. This request can be made of the higher-level business entity (as you’ll do later in this chapter), but the query itself should be prepared in the data access object. This is because that request requires defining a particular database query to get the rightOrderfrom the database.FILLevent logic that determines the final form of what is in the ProDataSet is part of the object. TheseFILLevent procedures can be associated with the ProDataSet instance at the time of theATTACH, as in these examples.In this way, all the definitions and code that reference the database are nicely captured in a single place. Here they can be maintained, as needed, when database definitions or data sources change. All the higher levels of access to the ProDataSet don’t contain any such references, which isolates them from the specifics of the Data-Sources. Once the
FILLevent procedures have been associated with the caller’s ProDataSet instance and the Data-Sources attached to it, the caller can simply execute theFILLmethod, and all the required logic is executed properly on that instance.So, let’s create the data access procedure
OrderSource.p.Much of the code in this procedure comes from the
OrderEvents.pprocedure in Chapter 7 "Advanced Events and Attributes". You can copy code from there and adapt it as needed. The purpose of this exercise is to begin to isolate the code better, based on what role it plays, to begin to provide more of an architecture to the application’s objects.In this example, the data access procedure has a static definition of the ProDataSet and its temp-tables:
As we noted in Chapter 7, "Advanced Events and Attributes,", it can help you isolate your ProDataSet definitions better if you can avoid this, but if there are many references to ProDataSet tables and fields in the
FILLlogic or elsewhere, then this might not be practical. This example shows the alternative of having the definitions in the data access procedure so that they can be referenced in static 4GL statements. As we work through the procedure, it will be important to note how the actual ProDataSet instance the code is operating on is not the one that this procedure gets by including the definitions. The support code is always using the instance from the requesting procedure.The top-level definition and the Data-Source definitions will be familiar from
OrderEvents.p, as shown:
OrderEvents.pwas intended to run as a stand-alone procedure with no internal procedures. Thus, it took theOrderNumberandOUTPUTProDataSet as parameters directly. In this case, the data access procedure runs as a persistent procedure, so it has no parameters. Instead, there is an internal procedure, calledfetchOrder, that implements this specific request for a singleOrder. Because it takesdsOrderas anINPUT-OUTPUTparameter, passedBY-REFERENCE, it is the caller’s instance of the ProDataSet that is used, not the one represented by the include files at the top ofOrderSource.p.The procedure uses the
QUERY-PREPAREmethod to get the right order, and then fills the ProDataSet, as shown:
The calling procedure runs the attach method (defined later) before running
fetchOrder, so that everything has been set up properly for theFILL. The code checks to make sure that there is a Data-Source for the top-level buffer before proceeding with theFILL. If not, it sets theERRORattribute for the ProDataSet and an error message on the top-level temp-table, which the caller can inspect.Later in this chapter, you’ll write another procedure that really represents the
Orderentity itself. This will have the ProDataSet instance that is actually used in the application, and it will define the API that other procedures, such as a client window, would use to access the ProDataSet. That API will include afetchOrderprocedure.Why, then, is this version of
fetchOrderhere in the data access procedure? Since it needs to use a specific database query to prepare the top-level table, it is better to put the procedure into the data access object. ThefetchOrderprocedure in theOrderentity itself will turn around and run this one to maintain the right level of encapsulation in the objects.Two of the
FILLevent procedures fromOrderEvents.pare preserved here,postOlineFillandpostItemRowFill. ProcedurepostOlineFillcalculates theOrderTotalin thettOrdertable, as shown:
Procedure
postItemRowFilledits theItemNamefield in thettItemtable, as shown:
There’s something important to note about these two procedures. They contain direct references to fields such as
ttItem.ItemName, which is possible because the temp-table definitions are included in the procedure. But remember that the local instance of the ProDataSet and its temp-tables is used for definition only. When Progress invokes these procedures during theFILL, it passes in the current ProDataSet instance implicitlyBY-REFERENCE. Progress not only adjusts all references to the ProDataSet itself to point to that external ProDataSet, but also all references to its temp-tables and their fields. This gives you the best of both worlds, as it were: a local static definition that makes the code simpler and clearer, but an automatic reference at run time to an externally defined ProDataSet that is passed into the procedure without any copying or other overhead.The code to attach the Data-Sources has been separated out, however, so that it can be executed not only for a
FILLbut also on a save. This is in the functionattachDataSet, which also runs theSET-CALLBACK-PROCEDUREfor the twoFILLevents, as shown:
There is also a corresponding
detachDataSetfunction:
|
Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095 |